/**
 * @description
 * Class to use HTML5 attribute placeholder
 * @example Placeholder.attach(input)
 * @author Alex Malyshev
 * @version 0.1
 */

/*
 * TODO: jQuery plugin
 */
Placeholder = function() {

    var ua = navigator.userAgent.toLowerCase();

    /** @type {Boolean} Is it MS IE browser */
    var msie = /msie/.test(ua) && !/opera/.test(ua);


    // checking for native placeholder support and required functions
    if ( ('placeholder' in document.createElement('input')) ||
         ( (!msie) && ( (!window.addEventListener) || (!window.getComputedStyle) ) )
       ) {
        return {
            attach: function(input) {
                return input;
            }
        }
    }

    /** @type {Array} font style css properties */
    var fontStyleParams = ['fontStyle', 'fontVariant', 'fontWeight', 'fontSize', 'fontFamily'];

    /**
     * Attach placeholder to input
     * @param {Object} input Input element
     * @param {String} text Placeholder text
     * @param {Boolean} [customFont] Use custom font flag
     */
    function attachPlaceholder(input, text, customFont) {
        var placeholder = document.createElement('span');
        placeholder.className = 'placeholder';
        placeholder.innerHTML = text;
        _clonePosition(input, placeholder);
        if (!customFont)
            _cloneFont(input, placeholder);
        input.__placeholder = placeholder;
        _attachEvent(placeholder, 'mousedown', function(e) {
            var e = e || window.event;
            hidePlaceholder(input);
            if (e.preventDefault) {
                input.focus();
                e.preventDefault();
            } else {
                // fix for ie6
                window.setTimeout(function() { input.focus();}, 50);
                e.returnValue = false;
            }
        });
        _attachEvent(input, 'focus', function() {
            hidePlaceholder(input);
        });
        _attachEvent(input, 'blur', function() {
            showPlaceholder(input);
        });

		if (input.value != '')
			hidePlaceholder(input);
        // check for non-empty input value after DOM loaded
        var _checkEmpty = function() {
            if (input.value != '')
                hidePlaceholder(input);
        }
        if (msie) {
            _attachEvent(document, 'readystatechange', _checkEmpty);
        } else {
            _attachEvent(document, 'DOMContentLoaded', _checkEmpty);
        }
    }

    /**
     * Hide placeholder for input
     * @param {Object} input Input element
     */
    function hidePlaceholder(input) {
        if ((input.__placeholder) && (!input.__placeholder.__hidden)) {
            input.__placeholder.style.display = 'none';
            input.__placeholder.__hidden = true;
        }
    }

    /**
     * Show placeholder for input
     * @param {Object} input Input element
     */

    function showPlaceholder(input) {
        if ((input.__placeholder) && (input.__placeholder.__hidden) && (input.value === '')) {
            input.__placeholder.innerHTML = input.getAttribute('placeholder');
            input.__placeholder.style.display = 'block';
            input.__placeholder.__hidden = false;
        }
    }

    /**
     * Place destination element over source element
     * @param {Object} src Source element
     * @param {Object} dest Destionation element
     * @return {Object} Desination element
     */
    function _clonePosition(src, dest) {
        // move source element to wrap
        var wrap = document.createElement('span');
        wrap.style.position = 'relative';
        wrap.style.display = 'block';
        src.parentNode.insertBefore(wrap, src);
        wrap.appendChild(src);
        var params = {
            left   : src.offsetLeft,
            top    : src.offsetTop,
            width  : src.clientWidth,
            height : src.clientHeight,
            paddingTop    : _getIStyle(src, 'borderTopWidth') + _getIStyle(src, 'paddingTop'),
            paddingRight  : _getIStyle(src, 'borderRightWidth') + _getIStyle(src, 'paddingRight'),
            paddingBottom : _getIStyle(src, 'borderBottomWidth') + _getIStyle(src, 'paddingBottom'),
            paddingLeft   : _getIStyle(src, 'borderLeftWidth') + _getIStyle(src, 'paddingLeft')
        };
        dest.style.position = 'absolute';
        dest.style.zIndex = _getIStyle(src, 'zIndex') + 1;
        dest.style.overflow = 'hidden';
        dest.style.whiteSpace = 'nowrap';
        // set cliping area to destionation element (right and bottom paddings)
        dest.style.clip = 'rect(auto, ' + (params.paddingLeft + params.width) + 'px, ' + (params.paddingTop + params.height) + 'px, auto)';
        dest.style.cursor = _getStyle(src, 'cursor');
        dest.style.lineHeight = _getStyle(src, 'lineHeight');
        for (var p in params) {
            dest.style[p] = params[p] + 'px';
        }
        wrap.appendChild(dest);
        return dest;
    }

    /**
     * Clone font css properties
     * @param {Object} src Source element
     * @param {Object} dest Destionation element
     * @return {Object} Desination element
     */
    function _cloneFont(src, dest) {
        var styleArray = [];
        for (var i = 0; i < fontStyleParams.length; i ++)
            styleArray.push(_getStyle(src, fontStyleParams[i]));
        dest.style.font = styleArray.join(' ');
        return dest;
    }

    /**
     * Get CSS style property for element
     * @param {Object} element Element
     * @param {String} name CSS property name
     * @return {String} CSS property value
     */
    function _getStyle(element, name) {
        name = name.replace(/([A-Z])/g, "-$1").toLowerCase();
        return window.getComputedStyle(element, '').getPropertyValue(name);
    }

    /**
     * Get ineger value of CSS style property
     * @param {Object} element Element
     * @param {String} name CSS property name
     * @return {Numer} Integer CSS property value
     */
    function _getIStyle(element, name) {
        var value = _getStyle(element, name);
        return ((value == null) || (value === 'auto')) ? 0 : parseInt(value);
    }

    /**
     * Bind event to element
     * @param {Object} element Source element
     * @param {String} Event Event name
     * @param {Function} method Callback function
     */
    function _attachEvent(element, event, method) {
        element.addEventListener(event, method, false);
        return element;
    }

    // MS IE fixes
    if (msie) {
        _getStyle = function(element, name) {
            return element.currentStyle[name];
        }
        _attachEvent = function(element, event, method) {
            element.attachEvent('on' + event, method);
            return element;
        }

    }

    return {
        /**
         * Attach placeholder to input element
         * @param {Object} input Input element
         * @param {Boolean} customFont Use custom font for placeholder element
         * @return {Object} Input element
         */
        attach: function(input, customFont) {
            if ((input) && (!input.__placeholder) && (input.getAttribute('placeholder') != undefined))
                attachPlaceholder(input, input.getAttribute('placeholder'), customFont)
            return input;
        }
    }
}();